package winapi

import (
	"fmt"
	"syscall"
	"unsafe"

	"github.com/lxn/win"
	"golang.org/x/sys/windows"
)

var (
	// Library
	libuser32 *windows.LazyDLL

	// Functions
	// getWindowTextA *windows.LazyProc
	// sendMessage   *windows.LazyProc
	vkKeyScan     *windows.LazyProc
	mapVirtualKey *windows.LazyProc
	getTopWindow  *windows.LazyProc
)

func init() {
	libuser32 = windows.NewLazySystemDLL("user32.dll")
	// getWindowTextA = libuser32.NewProc("GetWindowTextA")
	// sendMessage = libuser32.NewProc("SendMessageA")
	vkKeyScan = libuser32.NewProc("VkKeyScanA")
	mapVirtualKey = libuser32.NewProc("MapVirtualKeyA")
	getTopWindow = libuser32.NewProc("GetTopWindow")
}

// func SendMessage(hWnd win.HWND, msg uint32, wParam, lParam uintptr) (uintptr, error) {
// 	ret, _, err := syscall.Syscall6(sendMessage.Addr(), 4,
// 		uintptr(hWnd),
// 		uintptr(msg),
// 		wParam,
// 		lParam,
// 		0,
// 		0)
// 	if err != 0 {
// 		return 0, fmt.Errorf("syscall.Syscall failed, %s", err.Error())
// 	}

// 	return ret, nil
// }

func VkKeyScan(ch byte) (uint16, error) {
	ret, _, err := syscall.Syscall(vkKeyScan.Addr(), 1,
		uintptr(ch),
		0,
		0)
	if err != 0 {
		return 0, fmt.Errorf("syscall.Syscall failed, %s", err.Error())
	}

	return uint16(ret), nil
}
func MapVirtualKey(uCode uint32, uMapType uint32) (uint32, error) {
	ret, _, err := syscall.Syscall(mapVirtualKey.Addr(), 2,
		uintptr(uCode),
		uintptr(uMapType),
		0)
	if err != 0 {
		return 0, fmt.Errorf("syscall.Syscall failed, %s", err.Error())
	}

	return uint32(ret), nil
}

func GetTopWindow(hwnd win.HWND) (win.HWND, error) {
	ret, _, err := syscall.Syscall(getTopWindow.Addr(), 1,
		uintptr(hwnd),
		0,
		0)
	if err != 0 {
		return 0, fmt.Errorf("syscall.Syscall failed, %s", err.Error())
	}

	return win.HWND(ret), nil
}

func GetClassName(hwnd win.HWND) (string, error) {
	buf := make([]uint16, 512)
	_, err := win.GetClassName(hwnd, (*uint16)(unsafe.Pointer(&buf[0])), 512)
	if err != nil {
		return "", fmt.Errorf("win.GetClassName failed, %v", err)
	}
	return syscall.UTF16ToString(buf), nil
}

// GetWindowText 获取窗口文本
func GetWindowText(hwnd win.HWND) string {
	textLength := win.SendMessage(hwnd, win.WM_GETTEXTLENGTH, 0, 0)
	buf := make([]uint16, textLength+1)
	win.SendMessage(hwnd, win.WM_GETTEXT, uintptr(textLength+1), uintptr(unsafe.Pointer(&buf[0])))
	return syscall.UTF16ToString(buf)
}

// SetWindowText 设置窗口文本
func SetWindowText(hwnd win.HWND, text string) error {
	if win.TRUE != win.SendMessage(hwnd, win.WM_SETTEXT, 0, uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(text)))) {
		return fmt.Errorf("win.SendMessage WM_SETTEXT failed")
	}

	return nil
}

// SetDlgItemText 设置指定控件的标题
func SetDlgItemText(hwnd win.HWND, ctrlID int32, text string) error {
	ctrlWnd := win.GetDlgItem(hwnd, ctrlID)
	if ctrlWnd == 0 {
		return fmt.Errorf("没有找到控件ID:0x%x", ctrlID)
	}
	err := SetWindowText(ctrlWnd, text)
	if err != nil {
		return fmt.Errorf("SetWindowText failed, %v", err)
	}
	return nil
}

// GetDlgItemText 得到指定控件的标题
func GetDlgItemText(hwnd win.HWND, ctrlID int32) (string, error) {
	ctrlWnd := win.GetDlgItem(hwnd, ctrlID)
	if ctrlWnd == 0 {
		return "", fmt.Errorf("没有找到控件ID:0x%x", ctrlID)
	}
	return GetWindowText(ctrlWnd), nil
}

// FindChildWindowHasCtrl 查找有指定控件的子窗口
func FindChildWindowHasCtrl(hwnd win.HWND, ctrlID int32, title string) win.HWND {
	var childWnd win.HWND
	EnumChildWindows(hwnd, func(child win.HWND, lParam uintptr) (result uintptr) {
		// fmt.Printf("child: %x\n", child)
		text, err := GetDlgItemText(child, ctrlID)
		if err == nil && text == title {
			childWnd = child
			return 0
		}
		return 1
	}, 0)
	return childWnd
}

func FindClildWindow(hParent win.HWND, className string, title string) win.HWND {
	var hwnd win.HWND
	EnumChildWindows(hParent, func(child win.HWND, lParam uintptr) (result uintptr) {
		name, err := GetClassName(child)
		if err != nil {
			return 1
		}
		text := GetWindowText(child)
		// fmt.Println(name, text)

		if name == className && text == title {
			hwnd = child
			return 0
		}
		return 1
	}, 0)
	return hwnd
}

// EnumChildWindows 枚举子窗口
func EnumChildWindows(hwnd win.HWND, callback func(child win.HWND, lParam uintptr) (result uintptr), lParam uintptr) bool {
	enumChildProc := syscall.NewCallback(callback)
	return win.EnumChildWindows(hwnd, enumChildProc, 0)
}

// EnumPopupWindow 枚举弹出窗口,如果要枚举向下进行，需要关闭当前弹出窗口
func EnumPopupWindow(hwnd win.HWND, callback func(popup win.HWND)) {
	var lastPopWnd win.HWND
	for {
		popWnd := win.GetWindow(hwnd, win.GW_ENABLEDPOPUP)
		if popWnd == 0 {
			break
		}
		if lastPopWnd == popWnd {
			break
		}
		lastPopWnd = popWnd
		callback(popWnd)
	}
}

// KeybdEventCustom 使用 PostMessage API发送按键事件
func KeybdEventCustom(hwnd win.HWND, bVk uint32, dwFlag uint32) error {
	// var dwVKFkeyData uint32 = 1
	// dwScanCode := uint16(user32dll.MapVirtualKey(win.VK_F1, 0))
	// // dwVKFkeyData = 1
	// dwVKFkeyData |= uint32(dwScanCode << 16)
	// dwVKFkeyData |= 0 << 24
	// dwVKFkeyData |= 1 << 29

	ret := win.PostMessage(hwnd, uint32(bVk), uintptr(dwFlag), 0) //uintptr(dwVKFkeyData))
	if ret == 0 {
		errCode := win.GetLastError()
		return fmt.Errorf("win.PostMessage failed, error code: %v", errCode)
	}
	return nil
}
